<script lang="ts" setup>
import { computed, ref } from 'vue'

const init = ref<boolean>(false)
const isValid = ref<boolean>(false);
const result = ref<'empty' | 'valid' | 'invalid'>('empty');


// 注意：实现组件 v-model 的 value，时间名必须是 update:modelValue，对应 prop 名是 modelValue
// 实现组件 v-model 的 其它自定义属性类似
const props = withDefaults(defineProps<{
    modelValue: string,
    modelIsValid: boolean
    placeholder: string
}>(), {
    placeholder: "请输入密码"
})

const warnText = ref('')

function isValidPassword(): boolean {
    const password = props.modelValue;
  // 检查密码长度
  if (password.length < 8) {
    warnText.value = '密码长度不得小于8位';
    return false
  }

  // 检查特殊字符
  const invalidChars = /[/\\|?<>:* ]/;
  if (invalidChars.test(password)) {
    warnText.value = '密码中不得包含"/", "\\", "|", "?", "<", ">", ":", "*", 或空格';
    return false
  }

  // 检查是否同时包含数字、大小写字母
  const hasNumber = /\d/.test(password);
  const hasUpperCase = /[A-Z]/.test(password);
  const hasLowerCase = /[a-z]/.test(password);
  if (!hasNumber || !hasUpperCase || !hasLowerCase) {
    warnText.value = '密码中必须同时包含数字、大小写字母';
    return false
  }

  // 检查是否包含除了不能使用的特殊字符以外的其它特殊字符
  const specialChars = /[^a-zA-Z0-9/\\|?<>:* ]/;
  if (!specialChars.test(password)) {
    warnText.value = '密码中至少包含一个特殊字符';
    return false
  }

  // 密码符合要求
  return true
}

// 用于声明组件emit的事件。预期的参数与组件emit选项相同。
const emit = defineEmits<{
    // 声明输入密码发生更改事件参数类型
    (event: 'update:modelValue', value: string): void,
    // 声明密码已验证事件回调参数参数类型
    (event: 'passwordVerified', result: 'empty' | 'valid' | 'invalid'): void
}>()

// 实际上是，当触发原生 input 输入事件时，获取原生输入文本，作为组件 update:modelValue 事件的触发值
function handleInput($event: Event) {
    emit('update:modelValue', ($event.target as HTMLInputElement).value)
}

// 由原生的 blur 事件触发，一旦原生输入框失去焦点，直接将判断完是否是合法 密码 的结果作为事件的发布参数调用监听器
function handleBlur($event: Event) {
    init.value = true;
    const v = ($event.target as HTMLInputElement).value;
    if (v === '') {
        isValid.value = false;
        result.value = 'empty'
        // 密码为空字符串
        emit('passwordVerified', result.value);
    } else {
        isValid.value = isValidPassword();
        // 邮箱检验通过，触发邮箱已验证事件
        if (isValid.value) {
            result.value = 'valid'
            emit('passwordVerified', result.value);
        }
        else {
            // 邮箱检验不通过，还不是空字符串
            result.value = 'invalid'
            emit('passwordVerified', result.value);
        }
    }
}

// const shake = ref(false)

const eyeOpen = ref<boolean>(false);       // 表示输入框眼睛睁开状态

// 计算图标名
const eyeIconName = computed(() => {
  return eyeOpen.value ? 'eyes-open' : 'eyes-close'
})
// 计算密码输入框类型
const inputType = computed(() => {
  return eyeOpen.value ? 'text':'password'
})




function handleKeydown($event:Event){

}

</script>

<template>
<div class="password-group">
    <input 
      :type="inputType"
      :value="modelValue" 
      @input="$event => handleInput($event)"
      @blur="$event => handleBlur($event)"
      @keydown.enter="$event => handleKeydown($event)"
      :placeholder=placeholder
      
    />
    <jc-icon class="eye-icon" @click="($event:MouseEvent) => {eyeOpen = !eyeOpen}" :name="eyeIconName" />
</div>
    
    <p v-if="init" :class="{'input-warnnings':true, 'shake':init}">{{ warnText }}</p>
</template>

<style lang="scss" scoped>
input {
    border: none;
    padding: 9px 15px;
    margin: 8px 0;
    width: 100%;
}

p.input-warnnings {
    font-size: 12px;
    text-align: left;
    color: red;
}

@keyframes shake {
    0% {
        transform: translateX(0);
    }

    10%,
    30%,
    50%,
    70%,
    90% {
        transform: translateX(-5px);
    }

    20%,
    40%,
    60%,
    80% {
        transform: translateX(5px);
    }

    100% {
        transform: translateX(0);
    }
}

.shake {
  animation: shake 0.2s;
}
.re-shake{
  animation: shake 0.2s;
}
</style>